home *** CD-ROM | disk | FTP | other *** search
- 1 1 1 1 1 1 1 1 1 1 1 1 ] ]
-
-
- Eric's Fast Text Readln
- By Eric W. Wedaa
- 4620 E 17th St.
- Tucson AZ, 85711
- Bix :EWedaa
- CIS :76515.2274
- Feb 21, 1988
-
-
- I'll be honest here. I LOVE Pascal. It's a nice neat little
-
- language for writting programs, quite unlike some of the anarchist
-
- languages (C, assembly) or dinosaurs (B.A.S.I.C.) But there are
-
- times when even I'll admit that Personal Pascal has problems. The
-
- most glaring problem is doing a READ or a READLN.
-
-
- Now don't get me wrong, they work just fine in most
-
- instances. But they can be the most annoying function of Pascal
-
- when I have to read in 200K of text file from a RAM disk, or even
-
- worse, 200K off of a floppy disk. I can go to the coffee shop for
-
- lunch while I'm reading in all that text. Thankfully, O.S.S. has
-
- given us an extension that lets us call some of the GEMDOS
-
- routines from our code.
-
-
- My New Routines
-
- Well, I finally got sick of going to the coffee shop all the
-
- time. (The waitress's avoid me now, since they all know I'm a
-
- lousy tipper.) In the FASTREAD folder on the disk, you'll find
-
- my answer to the coffee shop blues. This program is a Pascal
-
- version of GEMDOS $3C, $3D, $3E, $3F, $40, $42 (Create, Open,
-
- Close, Read, Write, Seek). Using these routines in your program
-
- will make your READLN's between 7 and 12 times faster than the
-
- Pascal supplied READLN.
-
-
- One VERY new routine that doesn't exist in any other language that I
-
- know of is the F_Breadln routine. This was something I developed for one
-
- of my programe and thought others might find it handy. What it is a
-
- backwards readln routine. Instead of buffering the input yourself, (With
-
- all of those headaches, it uses the internal file buffer to do that for
-
- us. If you need to scan backwards several lines, just use this routine.
-
- It passes the strings back to you in a forward order. ("Hi there!"
-
- instead of "!ereht iH". You do have to be carefull of reading past the
-
- start of the file though. Weird things happen when you do. If you use
-
- this routine in your program, you need to check for an SOF (Start of
-
- file) flag. To get around the fact that this flag is set when you first
-
- open the file, use something similar to the following code:
-
- primed: boolean;
- |
- |
- |
- begin;
- |
- Primed := FALSE;
- While (Not EOF (file_buffer))
- and ((not primed) and (Not SOF (File_buffer)) do begin;
- Primed := TRUE;
- |
- |
- |
- ETC.
-
-
- This will get you into the file successfully.
-
-
- Using the Routines
-
- For those of you interested in just using these routines,
-
- this section is all you'll ever need to know. You'll need to put
-
- the constants, types, and the routines from FASTREAD.PAS into your
-
- program. Allthough they don't need to be global for your program,
-
- they do need to be declared in the same block of code that you'll
-
- be using the routines from. (Which probably means globally.)
-
-
- Now when you want to have a file for just reading from the
-
- disk, instead of declaring it as type FILE OF TEXT, just declare
-
- it instead as type BUFFER. Whenever you want to perform an action
-
- a disk file, just use the matching function from the chart below.
-
- You will still be passing parameters in the same order as with the
-
- Pascal functions. The two error routines require you to pass the
-
- buffer to them as well. You MUST do your own error checking with
-
- these routines!
-
- Fast Read Subroutines
-
- Pascal Fast Read
- Rewrite (File of TEXT, File name) F_Rewrite(Buffer, File name)
- Writeln (File of TEXT, String) F_Writeln(Buffer, String)
- Write (File of TEXT, String) F_Write(Buffer, String)
- Reset (File of TEXT, File name) F_Reset (Buffer, File name)
- Readln (File of TEXT, String) F_Readln (Buffer, String)
- Seek (File of TEXT, Integer) F_RSeek(Buffer, Pos):Boolean
- Close (File of TEXT) F_Close (Buffer)
- Eof (File of TEXT) F_Eof (Buffer)
- IO_Result F_Io_Result (Buffer)
- F_Error (Buffer)
- F_Breadln(Buffer, String);
-
-
- NOTE: F_RSeek is a function returning a BOOLEAN value. This
-
- is true if the seek suceeded, and false if it failed. This is
-
- for use while reading files ONLY! The File starts at 0, not 1.
-
-
- Notice though that these routines are set up just for
-
- READING or WRITING from or to a disk based file. (Ram, Hard, or
-
- Floppy disk.) This is not for reading from any of the ports, or
-
- more likely, to try to write to any of the ports.
-
-
- If you don't want to be reading in 255 byte strings, change
-
- the STRING_SIZE constant to the right size.
-
-
- Why it's Faster
-
- Doing a F_Readln or F_Writeln is increadibly fast. 7 to 12
-
- times faster in some cases. Great, but why? It has mainly to do
-
- with two areas we can't touch. The first is the file buffer
-
- size.
-
-
- When you declare a text file, Pascal only sets aside a small
-
- area of memory as a file buffer. When it's used, it has to call
-
- the disk up again and read another sector or two. In other words,
-
- it's always calling the disk, which entails spinning up the drive,
-
- finding the sector, reading the sector, and turning the drive off.
-
-
- When you use the Fast Read routines, we try and avoid the
-
- time spinning up the disk and searching for tracks and sectors
-
- from a stopped disk. Instead of reading or writing in 512 bytes
-
- at a time, we read or write in 15,000 bytes at a time. This way
-
- we don't lose time starting everything over again.
-
-
- The second reason is inherent in the way Pascal handles I/O.
-
- When you call a Pascal READLN, you can ask it to read in any kind
-
- of data. Integers, strings, booleans, reals, or records. Not
-
- only that, but you have them in your READLN in any order, and in
-
- any quantity. In other words, your I/O requests can be as sloppy
-
- as you want them to be.
-
-
- So if you use the following READLN--->READLN (in_File,
-
- An_Integer1, A_Real1, A_String1, A_Boolean, A_Real2);<--- then
-
- you're asking for time trouble. It has to first see if In_File is
-
- a file variable or not, and then it has to go through each of the
-
- variables seeing what type they are and the specifics on how to
-
- read each of them in. All this takes a lot of time.
-
-
- With the Fast Read routines, we avoid all of that. It knows
-
- that it's only reading or writing in strings from a text file.
-
- It knows the maximum string size allready. In other words,
-
- specialization is what makes this routine faster. Of course it
-
- costs a few more bytes, but if you're doing a lot of reading from
-
- text files, it makes it worth it.
-
-
- Development Details
-
-
- These routines are all based on GEMDOS functions $3C, $3D,
-
- $3E, $3F, $40 (Create, Open, Close, Read, Write). Allthough
-
- these GEMDOS functions have been described before, they have only
-
- been presented as a way to read in screen information, or large
-
- amounts of array information. Nothing on how to extract or
-
- insert strings from a one dimensional array.
-
-
- So I had the information on loading a plain vanilla one-
-
- dimension array. For strings, this is almost useless. There's
-
- just to much information you have to keep track of to read in a
-
- string to have a bunch of individual variables. So after
-
- figuring out what I needed to keep track of, I declared the
-
- following record:
-
- Buffer = RECORD
- Buffer_Contents : Contents ; { Contents of the buffer. }
- File_Handle : INTEGER ; { File handle. }
- Error_Number : INTEGER ; { Error Number if error occured. }
- No_Error : BOOLEAN ; { Was there no error occuring? }
- Buffer_Pos : LONG_INTEGER ; { Position to be read next. }
- Buffer_Len : LONG_INTEGER ; { How long is the buffer? }
- Last_Buffer : BOOLEAN ; { Is this the last buffer? }
- Eof_Buffer : BOOLEAN ; { Are we at the end of the file? }
- Reading_File : BOOLEAN ; { Are we reading this file? }
- Fast_Return : CHAR ; { Return character. }
- Fast_Line_Feed : CHAR ; { Line feed character. }
- Pos_In_File : LONG_INTEGER ; { What is the char count to the }
- { Start of this buffer? }
- End_Pos : LONG_INTEGER ; { What is the char count to the }
- { end of this buffer? }
-
- END ; {of type buffer}
-
-
- Now all I had to do was pass a single variable around,
-
- instead two or eight variables. (Also a neat way to speed up the
-
- routines.)
-
-
- Next, I had to write the GEMDOS calls, F_Create, F_Open,
-
- F_Read, F_Write, and F_Close. These came out of the O.S.S.
-
- release on using GEMDOS calls. (Available on their BBS, BIX, and
-
- CIS.)
-
-
- Then came the tricky part, writting the F_Reset, F_Rewrite,
-
- F_Readln, and F_Writeln routines. F_Rewrite converts the file
-
- name into C format and the calls F_Create (GEMDOS $3C.) It then
-
- initializes it's variables depending on whether an error occurred
-
- or not.
-
-
- F_Reset wasn't to hard once I figured out what I wanted it
-
- to do. It has to convert the file name into C format in order to
-
- pass it correctly. It then calls GEMDOS $3D to open the file.
-
- If it opens without an error, it then loads the Buffer_Contents
-
- array.
-
-
- The F_Read_File routine is where we load the buffer. If it
-
- successfully loads the buffer, it initializes the variables in the
-
- record. It then checks to see if it was the end of the file, and
-
- sets Last_Buffer to TRUE or FALSE, as is appropriate. If an error
-
- occurs, it sets all the variables to show this occurance.
-
-
- The hard part was to write the F_Readln routine. The first
-
- part I wrote was the area to just move characters from the buffer
-
- to the text string until we hit the last position in the buffer,
-
- or a Carriage Return character, or the string is filled.
-
-
- Then came the IF-THEN-ELSE statements to determine what to do
-
- next. The first in the series checks to see if the loop was left
-
- because it found a Return. If this was the case, it sets the
-
- length of the string equal to Counter. It then increments the
-
- Buffer_Pos by two to pass the Return and the Line Feed. If
-
- Buffer_Pos is greater than the length of the buffer it reloads
-
- the buffer again with a call to F_Read_File. It then resets
-
- Buffer_Pos to one or two to set the position to the first
-
- character in the buffer. It sets it to one if the first char-
-
- acter isn't a Line Feed, and to two if it is.
-
-
- If the program flow falls through the above test, it checks
-
- the next IF/THEN. This checks to see if the loop was exited
-
- because the string was full. If this was the case, then it sets
-
- the length of the string equal to counter and leaves Buffer_Pos
-
- alone.
-
-
- If the programs passes that IF/THEN it checks to see if the
-
- string loading was interupted because it ran out of buffer, and
-
- there was more information in the file (Not Last_Buffer.) If this
-
- was the case it reloads the buffer again and calls itself to
-
- finish reading the file. If an error occurs while reloading the
-
- buffer, it sets the string length to Count, and exits the routine.
-
-
- And lastly, it checks if the loop was done because it ran out
-
- of buffer and there wasn't any more information in the file. If
-
- this was the case, it sets the string length to Count again, and
-
- sets EOF_Buffer to true. It then exits the routine.
-
-
- The next set of routines are the Fast_Write routines. These
-
- were written after the Fast_Read routines were done. (Hence the
-
- program name.) These routines are F_Writeln and F_Write.
-
-
- F_Writeln was initially the F_Readln routine. I copied it
-
- once and modified it a bit. Instead of pulling characters from
-
- the main array (Buffer_Contents) it pushes them onto it. This
-
- allowed me to remove one of the loop tests (Look for Return)
-
- since there wasn't a Return in sight. When it exits the loop it
-
- sets Buffer_Len to the new length. If there's more room in
-
- Buffer_Contents it pushes a Ruturn/Line Feed onto the array.
-
- Otherwise, it writes out the array and adds a Return/Line Feed
-
- combination onto the start of the next array.
-
-
- The F_Eof, F_Error, and F_Error_Number routines were written
-
- just to help hide the data structure a little better. A user
-
- could (if s/he is really desperate to save time.) directly access
-
- the contents of the record instead of calling these routines.
-
-
- But I just finished a programming class where the teacher was
-
- big on "Hiding Data Structures" So I decided to hide the
-
- structure a little bit. That, and it makes it easier to convert
-
- my programs over to these routines. All I had to do was a global
-
- search and replace through my files to change Pascal routines into
-
- Fast routines.
-
-
- For a weekend project, this wasn't to hard to finish up. I
-
- think that this program shows a little bit more of the range of
-
- things that can be accomplished with O.S.S. Pascal. With access
-
- like this to the internal TOS and GEM routines, Who needs C?
-
- Certainly not me!
-
-
- References:
-
- Personal Pascal
- O.S.S.
- 1221B Kentwood Avenue
- San Jose, CA, 95129
- 408-446-3099
-